<template>
  <a-modal v-model="dialog" v-if="dialog"  width="100%" height="90%" :footer="null" wrapClassName="dialogClass" dialogClass="form-write-dialog flow-design-dialog" @opened="handleOpen" @cancel="handleClose">
   <div slot="title" style="height:20px;margin-top: -7px">
    <a-button-group>
      <a-tooltip placement="top" title="导入本地BPMN">
        <a-button @click="openFile">
          <a-icon type="import" style="font-size: 17px"/>
          <input ref="file" type="file" style="display: none" @change="showRealPath">
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="自适应">
        <a-button @click="fit()">
          <a-icon type="fullscreen-exit" style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="创建BPMN">
        <a-button @click="createProcess(processXml)">
          <a-icon type="plus" style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="下载XML">
        <a-button @click="exportDiagram">
          <a-icon type="file-excel" style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="下载图片">
        <a-button @click="saveSVG">
          <a-icon type="file-image" style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="放大">
        <a-button @click="zoom(0.2)">
          <a-icon type="zoom-in" style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="还原">
        <a-button @click="zoom(0)">
          <a-icon type="retweet" style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="缩小">
        <a-button @click="zoom(-0.2)">
          <a-icon type="zoom-out" style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="撤销" >
        <a-button @click="undo()" :disabled="redoNum==0">
          <a-icon type="undo" :rotate="100" style="font-size: 16px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="恢复">
        <a-button @click="redo()" :disabled="undoNum==0">
          <a-icon type="redo" :rotate="270" style="font-size: 16px"/>
        </a-button>
      </a-tooltip>
      <a-tooltip placement="top" title="保存">
        <a-button @click="saveXml()">
          <a-icon type="save"  style="font-size: 17px"/>
        </a-button>
      </a-tooltip>
      <!-- <a-button>
         <i class="icon-checkmark" title="验证模型"/>
       </a-button>-->
      <!-- <a-button @click="saveXml">
         <a-icon type="save"/>
       </a-button>-->
    </a-button-group>
   </div>
    <a-tabs v-model="activeName" type="card" class="custom-tabs" @change="handleTabClick" size="small">
      <a-tab-pane tab="流程设计器" key="1" style="margin-top:-17px">
        <a-layout id="wrap" class="wrap">
          <a-layout-content id="canvas" v-if="dialog" ref="canvas" class="canvas"/>
          <a-layout-sider class="aside" width="355px">
            <panel v-if="bpmnModeler&&dialog"  :modeler="bpmnModeler" :processDefinitionId="processDefinitionId" @change="optChange"  :typeid="typeid" :moddleType="moddleType" ref="panel" @callback="handleClose" />
          </a-layout-sider>
        </a-layout>
      </a-tab-pane>
      <a-tab-pane tab="流程XML" key="2" class="CodeMirror">
        <editor v-model="showXML" @init="editorInit"  :options="options"  lang="xml" theme="chrome" ></editor>
      </a-tab-pane>
    </a-tabs>
  </a-modal>
</template>

<script>
  //bpmn-js 设计器
  import Modeler from './CustomModeler'
  import MoveModule from 'diagram-js/lib/features/move'
  // 汉化
  import customTranslate from './CustomTranslate'
  // 右侧属性栏
  import propertiesPanelModule from './CustomPanel'
  //activiti实现类
  import activitiPropertiesProviderModule from './CustomPanel/lib/provider/activiti'
  //flowable实现类
  import flowablePropertiesProviderModule from './CustomPanel/lib/provider/activiti'
  //flowable描述文件
  import flowableModdleDescriptor from './CustomDescriptor/resources/flowable'
  //activiti描述文件
  import activitiModdleDescriptor from './CustomDescriptor/resources/activiti'
  //模版文件
  import templateXml_flowable from "./CustomDescriptor/resources/template_flowable";
  import templateXml_activiti from "./CustomDescriptor/resources/template_activiti";
  import FileSaver from 'file-saver'
  // global css
  import './style/index.less'
  import panel from './PropertyPanel/PropertyPanel'
  /*左边工具栏以及编辑节点的样式*/
  import 'bpmn-js/dist/assets/diagram-js.css'
  import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
  import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
  import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
  export default {
    name: 'FlymeFlowDesigner',
    components: {
      panel,
      editor: require('vue2-ace-editor')
    },
    props: {},
    data() {
      return {
        //引擎类型:flowable,activiti
        moddleType:'flowable',
        scale: 1,  //流程图比例（用于放大缩小）
        modelId: null,
        // bpmn建模器
        bpmnModeler: null,
        saveBtnEnabled:true,
        processDefinitionId:0,
        typeid:0,
        xmlStr: null,
        encodedData: null,
        formData: {},
        dialog: false,
        loading: false,
        title: '流程设计器',
        initTemplate: "",
        processXml: '',
        optNum:0,
        optType:1,
        undoNum:0,
        redoNum:0,
        showXML: '',
        customTranslate: {
          translate: ['value', customTranslate]
        },
        /*vue2-ace-editor编辑器配置*/
        options: {
          enableBasicAutocompletion: false,
          enableSnippets: true,
          fontSize:14,
          wrap:"free",
          readOnly:true,
          fixedWidthGutter:true,
          vScrollBarAlwaysVisible:false,
          wrapBehavioursEnabled:true,
          enableLiveAutocompletion: false
        },
        activeName: '1'
      }
    },
    created: function() {

    },
    mounted: function() {
      let processId = new Date().getTime();
      if(this.moddleType=='flowable')
      {
        this.processXml = templateXml_flowable.initTemplate(processId)
      }else{
        this.processXml = templateXml_activiti.initTemplate(processId)
      }
    },
    methods: {
       editorInit: function (ed) {
        require('brace');
        require('brace/ext/language_tools') //language extension prerequsite...
        require('brace/mode/xml')
        require('brace/theme/chrome')
        require('brace/snippets/javascript') //snippet
      },
      show(record) {
        this.dialog = true
        this.$nextTick(() => {
          this.handleOpen(record)
        })
      },
       //查询流程
      getProcess(processId) {
        if (processId === null) {
          return
        }
        this.http.get(this, {
          url: this.api.process.get,
          params: {
            processId: processId
          },
          success: function(me, data) {
            console.info('xml', data.processXml)
            me.$nextTick(() => {
              me.$refs.panel.setFormData(data)
              if (data.processXml) {
                me.createProcess(data.processXml)
              } else {
                me.createProcess(me.processXml)
              }
            })
          }
        })
      },
      async createProcess(xml) {
        try {
          const result = await this.bpmnModeler.importXML(xml)
          // this.bpmnModeler.get('canvas').viewbox({
          //   x: 30,
          //   y:  30,
          //   width:2157,
          //   height:1094,
          // })
          const { warnings } = result
        } catch (err) {
          console.log(err.message, err.warnings)
        }
      },
      handleOpen(record) {
        if (this.bpmnModeler) {
          return
        }
        //xml描述
        let moddleExtensions = this.getModdleExtensions();
        let providerModule=this.getProvider();
        // 创建Bpmn对象
        this.bpmnModeler = new Modeler({
          container: '#canvas',
          keyboard: {
            bindTo: window
          },
          additionalModules: [
            propertiesPanelModule,
            providerModule,
            this.customTranslate
          ],
          moddleExtensions: moddleExtensions
        })
        if (record && record.processId) {
          //编辑流程
          this.getProcess(record.processId)
          this.processDefinitionId=record.processId
          this.typeid=record.typeid;
        } else {
          //创建流程
          this.createProcess(this.processXml)
          this.processDefinitionId=0
          this.typeid=null
        }
      },
      handleClose() {
        //this.createProcess(this.processXml)
        this.bpmnModeler = null
        this.dialog = false
        this.activeName = '1'
        this.$emit('callback')
      },
      /**
       * 导出xml
       */
      exportDiagram() {
        this.bpmnModeler.saveXML({ format: true }, (err, xml)=> {
          if (!err) {
            let xmlName= this.$refs.panel.form.processName;
            FileSaver.saveAs(new Blob([xml], { type: 'application/octet-stream' }), xmlName+'.bpmn')
          }
        })
      },
      /**
       * 导出图片
       */
      async saveSVG() {
        try {
          const result = await this.bpmnModeler.saveSVG({ format: true });
          const { svg } = result;
          let xmlName= this.$refs.panel.form.processName;
          FileSaver.saveAs(new Blob([svg], { type: 'application/octet-stream' }), xmlName+'.svg')
        } catch (err) {
          console.log(err);
        }
      },
      async handleTabClick(key) {
        if (key === '2') {
          const _this = this
          try {
            const result = await this.bpmnModeler.saveXML({ format: true });
            const { xml } = result;
            _this.showXML = xml
          } catch (err) {
            console.log(err);
          }
        }
      },
      openFile() {
        this.$refs.file.dispatchEvent(new MouseEvent('click'))
      },
      showRealPath() {
        const selectedFile = this.$refs.file.files[0]
        // 后缀获取
        let suffix = ''
        try {
          const fileArr = selectedFile.name.split('.')
          suffix = fileArr[fileArr.length - 1]
        } catch (err) {
          suffix = ''
        }
        if (suffix === '' || (suffix !== 'xml' && suffix !== 'bpmn')) {
          alert('不是有效的流程文件！')
          return
        }
        // FileReader对象，h5提供的异步api，可以读取文件中的数据。
        const reader = new FileReader()
        // readAsText是个异步操作，只有等到onload时才能显示数据。
        reader.readAsText(selectedFile)
        const _this = this
        reader.onload = function() {
          // 当读取完成后回调这个函数,然后此时文件的内容存储到了result中,直接操作即可
          _this.createProcess(this.result)
        }
        // 防止选择同一个文件不执行此方法
        this.$refs.file.value = null
      },
      optChange(optType){
        if(optType==1){
          this.redoNum++;
          if(this.undoNum>0){
            this.undoNum--;
            if(this.undoNum==0){
              this.$refs.panel.setOptType(0)
            }
          }
        }else{
          this.undoNum++;
          if(this.redoNum>0)
          {
            this.redoNum--;
            if(this.redoNum==0){
              this.$refs.panel.setOptType(1)
            }
          }

        }
      },
      undo() {
        this.$refs.panel.setOptType(0)
        this.bpmnModeler.get('commandStack').undo()
      },
      // 流程图放大缩小
      zoom(radio) {
        const newScale = !radio ? 1.0 // 不输入radio则还原
          : this.scale + radio <= 0.2 // 最小缩小倍数
            ? 0.2
            : this.scale + radio
        this.bpmnModeler.get('canvas').zoom(newScale)
        this.scale = newScale
      },
      redo() {
        this.$refs.panel.setOptType(1)
        this.bpmnModeler.get('commandStack').redo()
      },
      fit() {
        this.bpmnModeler.get('canvas').zoom('fit-viewport', 'auto')
      },
      getModdleExtensions() {
        let moddleExtensions = {};
        if (this.moddleType == "flowable") {
          moddleExtensions = {
            flowable: flowableModdleDescriptor
          }
        }
        if (this.moddleType == "activiti") {
          moddleExtensions = {
            activiti: activitiModdleDescriptor
          }
        }
        return moddleExtensions;
      },
      saveXml(){
        this.$refs.panel.saveXml()
      },
      getProvider(){
        if (this.moddleType == "flowable") {
          return flowablePropertiesProviderModule;
        }
        if (this.moddleType == "activiti") {
          return activitiPropertiesProviderModule;
        }
      }
    }
  }

</script>

<style lang="less">

  .custom-tabs {
    margin-top: -23px;
    border-bottom: 1px solid #e0e0e0;
  }

  .bjs-powered-by {
    display: none;
  }
  .djs-direct-editing-parent{
    border-radius: 5px;
    border-bottom: 1px solid #000000;
    //update-begin--Author:scott  Date:20210323 for：双击节点，节点的四个角缺线样式问题
    background-color: transparent!important;
    border: 1px dashed rgb(204, 204, 204)!important;
    //update-end--Author:scott  Date:20210323 for：双击节点，节点的四个角缺线样式问题
  }
  .djs-direct-editing-content{

  }

  .djs-visual {
    margin-top: 5px;
  }

  .djs-palette {
    position: absolute;
    left: 20px;
    top: 10px;
  }

  .djs-palette.two-column.open {
    width:50px;
  }

  .dialogClass {
    margin-top: -100px;
  }

  .canvas {
    overflow: hidden;
    height: 90%;
  }

  .wrap {
    background: url('./data/bg.svg');
    height: calc(100vh - 122px);
  }

  .CodeMirror {
    height: calc(100vh - 122px);
  }

  .aside {
    background: #f8f8f8;
    height: 100%;
    border: 1px solid #e0e0e0;
    border-bottom: none;
  }
</style>
